﻿using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using net.xBei.Configurations;
using net.xBei.Helper;
using net.xBei.Models;
using net.xBei.Models.json;
using net.xBei.WebApi.Configurations;
using net.xBei.WebApi.Helper;

namespace net.xBei.WebApi.Repository;
/// <summary>
/// 内部微服务调用，“内部服务”的意思是：使用本框架搭建的同一项目系统下“API子服务站点”（微服务），使用统一的认证规则和调用规则（入口）
/// </summary>
public class ApiCallerFactory : IAutoRegisterSingleton {
    private readonly IHttpClientFactory clientFactory;
    private readonly IServer server;
    private readonly JwtSettings jwtSettings;
    private readonly ApiCallerSettings apiCallerSettings;
    private readonly ILogger logger;
    /// <summary>
    /// 当前服务名称
    /// </summary>
    public const string CurrentServiceName = "CURRENT";

    private readonly System.Collections.Concurrent.ConcurrentDictionary<string, ApiCaller> CallerList = [];
    private Uri CurrentUrl = default!;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="clientFactory"></param>
    /// <param name="server"></param>
    /// <param name="apiCallerSettings"></param>
    /// <param name="settings"></param>
    /// <param name="logger"></param>
    public ApiCallerFactory(IHttpClientFactory clientFactory,
                            IServer server,
                            IOptions<ApiCallerSettings> apiCallerSettings,
                            IOptions<JwtSettings> settings,
                            ILogger<ApiCallerFactory> logger) {
        this.clientFactory = clientFactory;
        this.server = server;
        jwtSettings = settings.Value;
        this.apiCallerSettings = apiCallerSettings.Value;
        this.logger = logger;
        GetLocalService(server);
    }

    private void GetLocalService(IServer server) {
        var uri = server.Features.Get<IServerAddressesFeature>()
                                ?.Addresses
                                .Select(address => new Uri(address))
                               .FirstOrDefault(uri => uri.Scheme == "http");
        if (uri == null) {
            Task.Run(async () => {
                Console.WriteLine("一秒钟以后重试");
                await Task.Delay(1000);
                GetLocalService(server);
                Console.WriteLine($"重试完成 {CurrentUrl}");
            });
            return;
        }
        if (uri.Host == "[::]") {
            uri = new Uri(uri.ToString().Replace("[::]", "localhost"));
        }
        var key = CurrentServiceName.MD5Encrypt();
        CurrentUrl = uri;
        CallerList[key] = new(clientFactory.CreateClient(),
                              new ApiCallerSettings.MicroService {
                                  Endpoint = uri,
                                  Version = "v1",
                                  Name = CurrentServiceName,
                                  TokenSecret = jwtSettings.TokenSecret,
                              },
                              getToken: () => GenerateSysToken(jwtSettings.TokenSecret),
                              logger);
    }
    /// <summary>
    ///  获取当前服务
    /// </summary>
    /// <returns></returns>
    public ApiCaller GetCurrentService() => GetService(CurrentServiceName);
    /// <summary>
    /// 获取认证（Token）服务
    /// </summary>
    /// <returns></returns>
    public ApiCaller GetTokenService() => string.IsNullOrWhiteSpace(jwtSettings.TokenService)
                                            ? GetService(CurrentServiceName)
                                            : GetService(jwtSettings.TokenService);
    /// <summary>
    /// 获取服务
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public ApiCaller GetService(string name) {
        if (name == CurrentServiceName) {
            if (!CallerList.ContainsKey(name.MD5Encrypt())) {
                GetLocalService(server);
            }
            return CallerList[name.MD5Encrypt()];
        }
        var settings = apiCallerSettings.Services.FirstOrDefault(s => s.Name == name) ?? throw new Exception($"未找到指定的服务：{name}");
        var key = $"{settings.Endpoint}-{settings.Version}".MD5Encrypt();
        if (CallerList.TryGetValue(key, out var caller)) {
            caller.FixEndpoint(CurrentUrl);
            return caller;
        }
        CallerList[key] = caller = new(clientFactory.CreateClient(),
                                       FixEndpoint(settings),
                                       getToken: () => GenerateSysToken(settings.TokenSecret ?? jwtSettings.TokenSecret),
                                       logger);
        return caller;
    }

    private ApiCallerSettings.MicroService FixEndpoint(ApiCallerSettings.MicroService settings) {
        if (settings.Endpoint.Host.Equals(CurrentServiceName, StringComparison.OrdinalIgnoreCase) && CurrentUrl != null) {
            // 替换成当前服务地址
            settings.Endpoint = CurrentUrl;
        }
        return settings;
    }

    /// <summary>
    /// 获取服务
    /// </summary>
    /// <param name="endpoint"></param>
    /// <param name="tokenSecret"></param>
    /// <returns></returns>
    public ApiCaller GetService(Uri endpoint, string? tokenSecret = default) {
        var settings = apiCallerSettings.Services.FirstOrDefault(s => s.Endpoint == endpoint);
        if (settings != null) {
            return GetService(settings.Name);
        }
        var key = endpoint.ToString().MD5Encrypt();
        if (CallerList.TryGetValue(key, out var caller)) {
            return caller;
        }
        CallerList[key] = caller = new(clientFactory.CreateClient(),
                                       new ApiCallerSettings.MicroService {
                                           Endpoint = endpoint,
                                           Version = "v1"
                                       },
                                       getToken: string.IsNullOrWhiteSpace(tokenSecret) ? null : () => GenerateSysToken(tokenSecret),
                                       logger: logger);
        return caller;
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="baseUrl"></param>
    /// <param name="path"></param>
    /// <param name="version"></param>
    /// <returns></returns>
    public static string ResolveRequestUri(string baseUrl, string path, string version = "v1") {
        if (baseUrl.EndsWith("/")) {
            baseUrl = baseUrl.TrimEnd('/');
        }
        if (baseUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase) == false
            && baseUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase) == false) {
            baseUrl = $"https://{baseUrl}";
        }
        if (path.StartsWith("/")) {
            path = path.TrimStart('/');
        }
        return $"{baseUrl}/api/{version}/{path}";
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="sysTokenSecret"></param>
    /// <param name="expires">过期时间（秒）</param>
    /// <returns></returns>
    public static string GenerateSysToken(string sysTokenSecret, int expires = 30) {
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(sysTokenSecret);
        var tokenDescriptor = new SecurityTokenDescriptor {
            Subject = new ClaimsIdentity(new Claim[] {
                new Claim(ClaimTypes.Name, CommonConsts.SystemUserId),
                new Claim("userId", "0"),
                new Claim(ClaimTypes.Role, "System")
            }),
            Expires = DateTime.UtcNow.AddSeconds(expires), // 30秒超时
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
        };
        var token = tokenHandler.CreateToken(tokenDescriptor);
        return tokenHandler.WriteToken(token);
    }
    /// <summary>
    /// 刷新Token
    /// </summary>
    /// <param name="claims"></param>
    /// <param name="tokenSecret"></param>
    /// <param name="expires">过期时间（秒）</param>
    /// <returns></returns>
    public static string GenerateToken(IEnumerable<Claim>? claims, string tokenSecret, int expires = 1800) {
        if (claims == null || !claims.Any()) {
            throw new ArgumentNullException(nameof(claims));
        }
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(tokenSecret);
        var tokenDescriptor = new SecurityTokenDescriptor {
            Subject = new ClaimsIdentity(claims),
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
            Expires = DateTime.UtcNow.AddSeconds(expires),
        };
        var token = tokenHandler.CreateToken(tokenDescriptor);
        return tokenHandler.WriteToken(token);
    }
}
/// <summary>
/// 
/// </summary>
public class ApiCaller {
    readonly HttpClient client;
    private readonly ApiCallerSettings.MicroService settings;
    private readonly Func<string, string?, string>? ResolveRequestUriAction;
    private readonly Func<string>? getToken;
    private readonly ILogger? logger;
    internal ApiCaller(HttpClient httpClient, ApiCallerSettings.MicroService settings, Func<string>? getToken = null, ILogger? logger = null) {
        client = httpClient;
        this.settings = settings;
        this.logger = logger;
        this.getToken = getToken;
    }
    //internal ApiCaller(HttpClient httpClient, string endpoint, string version = "v1", Func<string>? getToken = null, ILogger? logger = null) {
    //    client = httpClient;
    //    client.BaseAddress = new Uri(endpoint);
    //    this.version = version;
    //    this.getToken = getToken;
    //    this.logger = logger;
    //}
    //internal ApiCaller(HttpClient httpClient, string endpoint, Func<string, string> resolveRequestUri, Func<string>? getToken = null, ILogger? logger = null) {
    //    client = httpClient;
    //    client.BaseAddress = new Uri(endpoint);
    //    version = "v1";
    //    ResolveRequestUriAction = resolveRequestUri;
    //    this.getToken = getToken;
    //    this.logger = logger;
    //}
    /// <summary>
    /// 构建URL
    /// </summary>
    /// <param name="patch"></param>
    /// <param name="setQuery"></param>
    /// <returns></returns>
    public Uri BuildUrl(string patch, Func<Uri, Uri>? setQuery = null) {
        var uri = new UriBuilder(settings.Endpoint) {
            Path = patch,
        }.Uri;
        return setQuery?.Invoke(uri) ?? uri;
    }
    /// <summary>
    /// 安全的调用API
    /// </summary>
    /// <typeparam name="TResult"></typeparam>
    /// <param name="action"></param>
    /// <returns></returns>
    public async Task<ResponseData<TResult>> CatchAsync<TResult>(Func<ApiCaller, Task<TResult>> action) {
        try {
            var r = await action(this);
            return new ResponseData<TResult> { Success = true, Data = r, };
        } catch (ApiCallerException e) {
            LogError(client, e.Request, logger, e.Response, exception: e);
            return new ResponseData<TResult> { Code = 999999, Success = false, Message = e.Message };
        } catch (NeedLoginException e) {
            LogError(client, e.Request, logger, e.Response, exception: e);
            return new ResponseData<TResult> { Code = 401, Success = false, Message = "需要登录" };
        } catch (Exception e) {
            LogError(client: client, logger: logger, exception: e);
            throw;
        }
    }
    #region ResponseData
    /// <summary>
    /// 使用<see cref="HttpMethod.Get"/>调用<paramref name="path"/>接口并返回<see cref="ResponseData{T}"/>。
    /// </summary>
    /// <param name="path"></param>
    /// <param name="setQuery"></param>
    /// <param name="apiVersion"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<ResponseData<string>> GetResultAsync(string path, Func<Uri, Uri>? setQuery = null, string? apiVersion = default, string token = "") {
        var request = CreateRequest(method: HttpMethod.Get, api: path, setQuery: setQuery, body: null, apiVersion: apiVersion);
        FixToken(request, token);
        return await ExecuteResultAsync<string>(request);
    }
    /// <summary>
    /// 使用<see cref="HttpMethod.Get"/>调用<paramref name="path"/>接口并返回<see cref="ResponseData{T}" />。
    /// </summary>
    /// <typeparam name="TData"></typeparam>
    /// <param name="path"></param>
    /// <param name="setQuery"></param>
    /// <param name="apiVersion"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<ResponseData<TData>> GetResultAsync<TData>(string path, Func<Uri, Uri>? setQuery = null, string? apiVersion = default, string token = "") where TData : new() {
        var request = CreateRequest(method: HttpMethod.Get, api: path, setQuery: setQuery, body: null, apiVersion: apiVersion);
        FixToken(request, token);
        return await ExecuteResultAsync<TData>(request);
    }
    /// <summary>
    /// 使用<see cref="HttpMethod.Post"/>调用<paramref name="path"/>接口并返回<see cref="ResponseData{T}"/>。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="path"></param>
    /// <param name="setQuery"></param>
    /// <param name="body">如果传入<see cref="string"/>会直接作为JSON字串处理</param>
    /// <param name="apiVersion"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<ResponseData<T>> PostResultAsync<T>(string path,
                                                          Func<Uri, Uri>? setQuery = null,
                                                          object? body = null,
                                                          string? apiVersion = default,
                                                          string token = "") {
        var request = CreateRequest(method: HttpMethod.Post, api: path, setQuery: setQuery, body: body, apiVersion: apiVersion);
        FixToken(request, token);
        return await ExecuteResultAsync<T>(request);
    }
    /// <summary>
    /// 使用<see cref="HttpMethod.Put"/>调用<paramref name="path"/>接口并返回<see cref="ResponseData{T}"/>。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="path"></param>
    /// <param name="setQuery"></param>
    /// <param name="body">如果传入<see cref="string"/>会直接作为JSON字串处理</param>
    /// <param name="apiVersion"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<ResponseData<T>> PutResultAsync<T>(string path, Func<Uri, Uri>? setQuery = null, object? body = null, string? apiVersion = default, string token = "")
         where T : new() {
        var request = CreateRequest(method: HttpMethod.Put, api: path, setQuery: setQuery, body: body, apiVersion: apiVersion);
        FixToken(request, token);
        return await ExecuteResultAsync<T>(request);
    }
    /// <summary>
    /// 使用<see cref="HttpMethod.Delete"/>调用<paramref name="path"/>接口并返回<see cref="ResponseData{T}"/>。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="path"></param>
    /// <param name="setQuery"></param>
    /// <param name="body">如果传入<see cref="string"/>会直接作为JSON字串处理</param>
    /// <param name="apiVersion"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<ResponseData<T>> DeleteResultAsync<T>(string path, Func<Uri, Uri>? setQuery = null, object? body = null, string? apiVersion = default, string token = "") where T : new() {
        var request = CreateRequest(method: HttpMethod.Delete, api: path, setQuery: setQuery, body: body, apiVersion: apiVersion);
        FixToken(request, token);
        return await ExecuteResultAsync<T>(request);
    }

    #endregion
    #region call
    /// <summary>
    /// 使用<see cref="HttpMethod.Get"/>调用<paramref name="api"/>接口
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="api"></param>
    /// <param name="setQuery"></param>
    /// <param name="apiVersion"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<T?> GetAsync<T>(string api, Func<Uri, Uri>? setQuery = null, string? apiVersion = default, string token = "") where T : new() {
        var request = CreateRequest(method: HttpMethod.Get, api: api, setQuery: setQuery, body: null, apiVersion: apiVersion);
        FixToken(request, token);
        return await ExecuteAsync<T>(request);
    }
    /// <summary>
    /// 使用<see cref="HttpMethod.Post"/>调用<paramref name="api"/>接口
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="api"></param>
    /// <param name="setQuery"></param>
    /// <param name="body">如果传入<see cref="string"/>会直接作为JSON字串处理</param>
    /// <param name="apiVersion"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<T?> PostAsync<T>(string api, Func<Uri, Uri>? setQuery = null, object? body = null, string? apiVersion = default, string token = "") where T : new() {
        var request = CreateRequest(method: HttpMethod.Post, api: api, setQuery: setQuery, body: body, apiVersion: apiVersion);
        FixToken(request, token);
        Console.WriteLine($"POST({request.RequestUri}):{body?.ToJson(true)}");
        return await ExecuteAsync<T>(request);
    }

    /// <summary>
    /// 使用<see cref="HttpMethod.Put"/>调用<paramref name="api"/>接口
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="api"></param>
    /// <param name="setQuery"></param>
    /// <param name="body">如果传入<see cref="string"/>会直接作为JSON字串处理</param>
    /// <param name="apiVersion"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<T?> PutAsync<T>(string api, Func<Uri, Uri>? setQuery = null, object? body = null, string? apiVersion = default, string token = "") where T : new() {
        var request = CreateRequest(HttpMethod.Put, api, setQuery, body, apiVersion);
        FixToken(request, token);
        return await ExecuteAsync<T>(request);
    }
    /// <summary>
    /// 使用<see cref="HttpMethod.Delete"/>调用<paramref name="api"/>接口
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="api"></param>
    /// <param name="setQuery"></param>
    /// <param name="body">如果传入<see cref="string"/>会直接作为JSON字串处理</param>
    /// <param name="apiVersion"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<T?> DeleteAsync<T>(string api, Func<Uri, Uri>? setQuery = null, object? body = null, string? apiVersion = default, string token = "") where T : new() {
        var request = CreateRequest(HttpMethod.Delete, api, setQuery, body, apiVersion);
        FixToken(request, token);
        return await ExecuteAsync<T>(request);
    }
    #endregion
    #region 私有
    private HttpRequestMessage CreateRequest(HttpMethod method,
                                             string api,
                                             Func<Uri, Uri>? setQuery = null,
                                             object? body = null,
                                             string? apiVersion = "v1") {
        if (body == null) {
            return new HttpRequestMessage(method, GetApiUrl(api, apiVersion, setQuery));
        }
        return new HttpRequestMessage(method, GetApiUrl(api, apiVersion, setQuery)) {
            Content = body is string str
                            ? new StringContent(str, System.Text.Encoding.UTF8, "application/json")
                            : JsonContent.Create(body)
        };
    }
    private Uri GetApiUrl(string api, string? apiVersion = default, Func<Uri, Uri>? setQuery = null) {
        var uri = new UriBuilder(settings.Endpoint) {
            Path = ResolveRequestUri(api, apiVersion),
        }.Uri;
        return setQuery?.Invoke(uri) ?? uri;
    }
    private string ResolveRequestUri(string path, string? version = null) {
        return ResolveRequestUriAction == null
                    ? path.StartsWith("/")
                        ? path.Replace("/{version}/", $"/{version ?? settings.Version}/")
                        : $"api/{version ?? settings.Version}/{path}"
                    : ResolveRequestUriAction.Invoke(path, version);
    }
    private string FixToken(string? token)
        => string.IsNullOrWhiteSpace(token)
            ? getToken?.Invoke() ?? string.Empty
            : token;
    private void FixToken(HttpRequestMessage request, string? token = default) {
        token = FixToken(token);
        if (!string.IsNullOrWhiteSpace(token)) {
            request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
            //Console.WriteLine($"Authorization:Bearer {token}");
        }
    }
    private async Task<ResponseData<T>> ExecuteResultAsync<T>(HttpRequestMessage request) {
        try {
            return await ExecuteAsync<ResponseData<T>>(request).IsEmptyAsync(ResponseData<T>.Error("未知错误"));
        } catch (ApiCallerException e) {
            LogError(client, request, logger, e.Response, exception: e);
            return new ResponseData<T> { Code = 999999, Success = false, Message = e.Message };
        } catch (NeedLoginException e) {
            LogError(client, e.Request, logger, e.Response, exception: e);
            return new ResponseData<T> { Code = 401, Success = false, Message = "需要登录" };
        } catch (Exception e) {
            LogError(client, request, logger, exception: e);
            throw;
        }
    }

    private async Task<T?> ExecuteAsync<T>(HttpRequestMessage request) {
        LogDebug(client, request, logger);
        var r = await client.SendAsync(request);
        LogDebug(client, request, logger, r);
        return r.StatusCode switch {
            System.Net.HttpStatusCode.NotFound => throw new ApiCallerException(request, r, $"未找到：[{request.Method}] {request.RequestUri}"),
            System.Net.HttpStatusCode.Unauthorized or System.Net.HttpStatusCode.Forbidden => throw new NeedLoginException(request, r),
            System.Net.HttpStatusCode.BadRequest => await FixBadRequestAsync<T>(r),
            System.Net.HttpStatusCode.NoContent => default,
            System.Net.HttpStatusCode.OK or System.Net.HttpStatusCode.Accepted or System.Net.HttpStatusCode.Created
            => typeof(T).Equals(typeof(string))
                ? JsonHelper.TryDeserialize<T>($"\"{await r.Content.ReadAsStringAsync()}\"")
                : await r.Content.ReadFromJsonAsync<T>(),
            _ => throw new ApiCallerException(request, r, r.ReasonPhrase),
        };
    }

    private static async Task<T> FixBadRequestAsync<T>(HttpResponseMessage r) {
        try {
            var json = await r.Content.ReadAsStringAsync();
            if (json.TryDeserialize<T>(out var data)) {
                return data;
            }
            throw new Exception(json);
        } catch {
            throw;
        }
    }
    #endregion
    #region 日志
    static void LogDebug(HttpClient client, HttpRequestMessage? request = default, ILogger? logger = default, HttpResponseMessage? response = default)
        => Log(LogLevel.Debug, client, request, logger, response);
    static void LogInfo(HttpClient client, HttpRequestMessage? request = default, ILogger? logger = default, HttpResponseMessage? response = default)
        => Log(LogLevel.Information, client, request, logger, response);
    static void LogError(HttpClient client, HttpRequestMessage? request = default, ILogger? logger = default, HttpResponseMessage? response = default, Exception? exception = default)
        => Log(LogLevel.Error, client, request: request, logger: logger, response: response, exception: exception);
    static void Log(LogLevel level, HttpClient client, HttpRequestMessage? request = default, ILogger? logger = default, HttpResponseMessage? response = default, Exception? exception = default) {
        logger?.Log(
            logLevel: level,
            eventId: new EventId(0, "ApiCaller"),
            state: new {
                Request = new {
                    Method = request?.Method.ToString(),
                    request?.RequestUri,
                    Header = request?.Headers.ToList(),
                    //Query = request.Parameters.Where(p => p.Type == ParameterType.QueryString).ToList(),
                    Body = request?.Method == HttpMethod.Get ? null : request?.Content?.ReadAsStringAsync().Result,
                },
                Response = new {
                    response?.StatusCode,
                    response?.ReasonPhrase,
                    Content = response?.Content.ReadAsStringAsync().Result,
                },
            },
        exception: exception,
        formatter: (obj, ex) => obj.ToJson(true));
    }
    #endregion
    #region 快捷方法
    /// <summary>
    /// 检查用户权限
    /// </summary>
    /// <param name="userId"></param>
    /// <param name="controller"></param>
    /// <param name="action"></param>
    /// <param name="permissionKey"></param>
    /// <returns></returns>
    public async Task<bool> CheckUserPermissionAsync(int userId, string controller, string action, string permissionKey) {
        var r = await PostResultAsync<object>("User/CheckUserPermission",
                                                      body: new { UserId = userId, Controller = controller, Action = action, PermissionKey = permissionKey });
        return r.Success;
    }

    internal void FixEndpoint(Uri currentUrl) {
        if (settings.Endpoint.Host.Equals(ApiCallerFactory.CurrentServiceName, StringComparison.OrdinalIgnoreCase) && currentUrl != null) {
            // 替换成当前服务地址
            settings.Endpoint = currentUrl;
        }
    }
    #endregion
    /// <summary>
    /// 需要登陆时触发
    /// </summary>
    public class NeedLoginException : Exception {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="request"></param>
        /// <param name="response"></param>
        public NeedLoginException(HttpRequestMessage? request, HttpResponseMessage? response)
            : base("需要登陆") {
            Request = request;
            Response = response;
        }
        /// <summary>
        /// 
        /// </summary>
        public HttpRequestMessage? Request { get; }
        /// <summary>
        /// 
        /// </summary>
        public HttpResponseMessage? Response { get; }
    }
    /// <summary>
    /// 调用API时发生的错误
    /// </summary>
    public class ApiCallerException : Exception {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="request"></param>
        /// <param name="response"></param>
        /// <param name="message"></param>
        public ApiCallerException(HttpRequestMessage? request, HttpResponseMessage? response, string? message) : base(message ?? "未知错误") {
            Request = request;
            Response = response;
        }
        /// <summary>
        /// 
        /// </summary>
        public HttpRequestMessage? Request { get; }
        /// <summary>
        /// 
        /// </summary>
        public HttpResponseMessage? Response { get; }
    }
}// end class
